#pragma once

#include <iostream>
#include <thread>
#include <assert.h>
#include <unistd.h>
using std::cout;
using std::endl;

static const size_t NFREELIST = 208;// 桶的数量
static const size_t MAX_BYTES = 256 * 1024;// ThreadCache可申请的最大内存空间

// 返回传入块空间的头4个或8个字节内存的引用
static inline void*& GetNextObj(void* obj)
{
  return *(void**)obj;
}

// 管理切分好的定长大小块空间的自由链表
class FreeList
{
  public:
    void Push(void* obj)
    {
      assert(obj);
      // 头插
      GetNextObj(obj) = _freeList;
      _freeList = obj;
    }

    void* Pop()
    {
      assert(_freeList);
      // 头删
      void* obj = _freeList;
      _freeList = GetNextObj(obj);
      return obj;
    }

    bool Empty()
    {
      return _freeList == nullptr;
    }

  private:
    void* _freeList = nullptr;
};

// 计算传入对象大小的对齐映射规则
class SizeClass
{
  // 整体控制在最多10%左右的内碎片浪费
	// [1,128]				      	8byte对齐	       freelist[0,16)
	// [128+1,1024]			    	16byte对齐	     freelist[16,72)
	// [1024+1,8*1024]		  	128byte对齐	     freelist[72,128)
	// [8*1024+1,64*1024]	  	1024byte对齐     freelist[128,184)
	// [64*1024+1,256*1024]		8*1024byte对齐   freelist[184,208)
  
  // 计算对齐后得到的块大小
  public:
    static inline size_t RoundUp(size_t bytes)
    {
      if(bytes <= 128)
      {
        return _RoundUp(bytes, 8);
      }
      else if(bytes <= 1024)
      {
        return _RoundUp(bytes, 16);
      }
      else if(bytes <= 8*1024)
      {
        return _RoundUp(bytes, 128);
      }
      else if(bytes <= 64*1024)
      {
        return _RoundUp(bytes, 1024);
      }
      else if(bytes <= 256*1024)
      {
        return _RoundUp(bytes, 8*1024);
      }
      else 
      {
        assert("ThreadCache over 256k\n");
        return -1;
      }
    }

    // 计算映射到哪一个哈希自由链表桶
    static inline size_t Index(size_t bytes)
    {
      // 记录每一个对齐区间有多少个桶
	    static int group_array[4] = { 16, 56, 56, 56 };
      // 根据传入的对象大小映射得到自由链表桶对应的下标
      if (bytes <= 128){
			return _Index(bytes, 3);
		  }
		  else if (bytes <= 1024){
		  	return _Index(bytes - 128, 4) + group_array[0];
		  }
		  else if (bytes <= 8 * 1024){
		  	return _Index(bytes - 1024, 7) + group_array[1] + group_array[0];
		  }
		  else if (bytes <= 64 * 1024){
		  	return _Index(bytes - 8 * 1024, 10) + group_array[2] + group_array[1] + group_array[0];
		  }
		  else if (bytes <= 256 * 1024){
		  	return _Index(bytes - 64 * 1024, 13) + group_array[3] + group_array[2] + group_array[1] + group_array[0];
		  }
		  else{
        assert("ThreadCache over 256k\n");
        return -1;
		  }
    }
  
  private:
    static inline size_t _RoundUp(size_t bytes, size_t alignNum)
	  {
	  	return ((bytes + alignNum - 1) & ~(alignNum - 1));
	  }

    static inline size_t _Index(size_t bytes, size_t align_shift)
	  {
	  	return ((bytes + (1 << align_shift) - 1) >> align_shift) - 1;
	  }
};
